/******************************************************************************
 Copyright (c) 2024-2025 Qualcomm Technologies International, Ltd.
 All Rights Reserved.
 Qualcomm Technologies International, Ltd. Confidential and Proprietary.

******************************************************************************/

#include "gatt_ras_server_private.h"
#ifdef INSTALL_CHANNEL_SOUNDING_SUPPORT

#include "gatt_ras_server_debug.h"
#include "gatt_ras_server_msg_handler.h"
#include "gatt_ras_server_notify_indicate.h"
#include "gatt_ras_server_access.h"
#include "csr_bt_cm_lib.h"
#include "csr_bt_cm_prim.h"

bool GattRasServerFlushRangingData(RasServiceHandleType handle, ConnectionIdType cid, uint16 rangingCounter)
{
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);
    uint8 client_index = rasServerGetCidIndex(rasServer,cid);

    GATT_RAS_SERVER_INFO("RAS: GattRasServerFlushRangingData: cid =0x%x", cid);

    if(rangingCounter != rasServer->data.connectedClients[client_index].curRangingCounter)
    {
        return FALSE;
    }

    /* Free the list */
    rasServerFreeRangingDataList(rasServer, client_index);

    rasServer->data.connectedClients[client_index].rangingDataRequested = FALSE;

    /* Reset number of segments */
    rasServer->data.connectedClients[client_index].numOfSegments =0;
    rasServer->data.connectedClients[client_index].allSegmentsSent = FALSE;

    return TRUE;

}
bool GattRasServerRangingDataReady(RasServiceHandleType handle, ConnectionIdType cid, uint16 rangingCounter)
{
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);
    uint8 client_index;

    uint8 data[GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE];

    if (rasServer == NULL)
        return FALSE;

    GATT_RAS_SERVER_INFO("RAS: GattRasServerRangingDataReady: cid =0x%x", cid);

    client_index = rasServerGetCidIndex(rasServer,cid);

    rasServer->data.connectedClients[client_index].curRangingCounter = rangingCounter;

    rasServer->data.connectedClients[client_index].procedureActive = TRUE;

    data[0] = (uint8)(rangingCounter & 0xFF);
    data[1] = (uint8)(rangingCounter >> 8) & 0xFF;

    rasServerSendRasData(
        rasServer,
        cid,
        HANDLE_RANGING_DATA_READY,
        GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE,
        data);

    return TRUE;
}

bool GattRasServerCompleteRangingDataResponse(RasServiceHandleType handle,
    ConnectionIdType cid,
    uint16 rangingCounter)
{
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);
    uint8 client_index;

    if (rasServer == NULL)
        return FALSE;

    client_index = rasServerGetCidIndex(rasServer,cid);

    rasServerRasCpCompleteRangingDataResponse(rasServer, cid, rangingCounter);

    rasServer->data.connectedClients[client_index].procedureActive = FALSE;

    return TRUE;
}

bool GattRasServerCompleteLostRangingDataSegmentResponse(RasServiceHandleType handle,
    ConnectionIdType cid,
    uint16 rangingCounter,
    uint8 startSegment,
    uint8 endSegment)
{
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);

    if (rasServer == NULL)
        return FALSE;

    rasServerRasCpCmpLostRangingDataSegResponse(
        rasServer,
        cid,
        rangingCounter,
        startSegment,
        endSegment);

    return TRUE;
}

bool GattRasServerRangingDataOverwritten(RasServiceHandleType handle, ConnectionIdType cid, uint16 rangingCounter)
{
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);
    uint8 data[GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE];

    if (rasServer == NULL)
        return FALSE;

    data[0] = (uint8)(rangingCounter & 0xFF);
    data[1] = (uint8)(rangingCounter >> 8) & 0xFF;

    rasServerSendRasData(
        rasServer,
        cid,
        HANDLE_RANGING_DATA_OVERWRITTEN,
        GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE,
        data);

    return TRUE;
}

/******************************************************************************/
GattRasServerConfigType *GattRasServerRemoveConfig(RasServiceHandleType handle,
    ConnectionIdType cid)
{
    uint8 client_index;
    GattRasServerConfigType *client_config = NULL;
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);

    if (rasServer == NULL)
        return client_config;

    for(client_index =0; client_index <GATT_RAS_MAX_CONNECTIONS; client_index++)
    {
        /* Check the saved CID to find the peer device */
        if (rasServer->data.connectedClients[client_index].cid == cid)
        {
            /* Found peer device:
             * - save last client configurations
             * - remove the peer device
             * - free the server instance
             * - return last client configuration
             */
            GATT_RAS_SERVER_INFO("GattRasServerRemoveConfig cid:0x%x", cid);

            client_config = CsrPmemZalloc(sizeof(GattRasServerConfigType));
            memcpy(client_config, &(rasServer->data.connectedClients[client_index].clientCfg), sizeof(GattRasServerConfigType));

            /* Free the list */
            rasServerFreeRangingDataList(rasServer, client_index);
            
            rasServer->data.connectedClients[client_index].rangingDataRequested = FALSE;
            
            /* Reset number of segments */
            rasServer->data.connectedClients[client_index].numOfSegments =0;
            
            rasServer->data.connectedClients[client_index].triggerCsProcedureComplete = FALSE;

            if ((client_index == (GATT_RAS_MAX_CONNECTIONS-1)) || (client_index == 0 && rasServer->data.connectedClients[client_index+1].cid == 0))
            {
                /* The peer device is the only or the last element of the array */
                memset(&(rasServer->data.connectedClients[client_index]), 0, sizeof(ras_client_data));
            }
            else
            {
                /* The peer device is in the middle of the array */
                uint8 j;
            
                for (j=client_index; j< (GATT_RAS_MAX_CONNECTIONS -1) && rasServer->data.connectedClients[j+1].cid != 0; j++)
                {
                    /* Shift all the elements of the array of one position behind */
                    memmove(&(rasServer->data.connectedClients[j]),
                           &(rasServer->data.connectedClients[j+1]),
                           sizeof(ras_client_data));
                }
            
                /* Remove the last element of the array, already shifted behind */
                memset(&(rasServer->data.connectedClients[j]), 0, sizeof(ras_client_data));
            }
            break;
        }
    }

    return client_config;
}

/******************************************************************************/
status_t GattRasServerAddConfig(RasServiceHandleType handle,
    ConnectionIdType cid,
    GattRasServerConfigType *config)
{
    uint8 i, j;
    status_t res = CSR_BT_GATT_RESULT_CANCELLED;

    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);

    if (rasServer == NULL)
        return CSR_BT_GATT_RESULT_INTERNAL_ERROR;
        
    if (rasServerGetCidIndex(rasServer, cid) != GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        GATT_RAS_SERVER_INFO("GattRasServerAddConfig connection exits error cid:0x%x", cid);
        return CSR_BT_GATT_RESULT_ALREADY_CONNECTED;
    }

    for(i=0; i<GATT_RAS_MAX_CONNECTIONS; i++)
    {
        if(rasServer->data.connectedClients[i].cid == 0 )
        {
            rasServer->data.connectedClients[i].cid = cid;

            GATT_RAS_SERVER_INFO("GattRasServerAddConfig cid:0x%x", cid);

            /* Check config parameter:
             * If config is NULL, it indicates a default config should be used for the
             * peer device identified by the CID.
             * The default config is already set when the instance has been initialised.
             */
            if (config)
            {
                /* Save new ccc for the client */
                rasServer->data.connectedClients[i].clientCfg.realTimeDataClientCfg = config->realTimeDataClientCfg;
                rasServer->data.connectedClients[i].clientCfg.onDemandDataClientCfg = config->onDemandDataClientCfg;
                rasServer->data.connectedClients[i].clientCfg.controlPointClientCfg = config->controlPointClientCfg;
                rasServer->data.connectedClients[i].clientCfg.dataReadyClientCfg = config->dataReadyClientCfg;
                rasServer->data.connectedClients[i].clientCfg.dataOverwrittenClientCfg = config->dataOverwrittenClientCfg;


                /* Notify the connected client for values for CCCD which are set */
                /* TBD */
            }

            for(j = 0; j < GATT_RAS_SERVER_NUM_OF_MODES; j++)
            {
                rasServer->data.connectedClients[i].filterMask[j] = 0xFFFF;
            }

            rasServer->data.connectedClients[i].rangingDataList = NULL;

            rasServer->data.connectedClients[i].rollingCounter = 0;
            rasServer->data.connectedClients[i].mtu = RAS_DEFAULT_MTU;
            res = CSR_BT_GATT_RESULT_SUCCESS;
            break;
        }
    }

    if (res)
    {
        res = CSR_BT_GATT_RESULT_INSUFFICIENT_NUM_OF_HANDLES;
    }

    return res;
}

bool GattRasServerSetRangingDataMtu(
                          RasServiceHandleType handle,
                          ConnectionIdType cid,
                          uint16 remoteRxMtu) 
{
    uint16 clientIndex ;
    GRASS_T *rasServer = (GRASS_T *) ServiceHandleGetInstanceData(handle);
    if (rasServer == NULL)
        return FALSE;

    clientIndex = rasServerGetCidIndex(rasServer, cid);
    if(clientIndex ==GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        return FALSE;
    }
    GATT_RAS_SERVER_INFO("RAS: GattRasServerSetRangingDataMtu: cid =0x%x, remoteRxMtu: 0x%x, clientIndex: 0x%x", cid, 
    remoteRxMtu, clientIndex);
    rasServer->data.connectedClients[clientIndex].mtu = remoteRxMtu;
    return TRUE;
}

#endif /* INSTALL_CHANNEL_SOUNDING_SUPPORT */